#!/bin/sh

e2e_exclusive_lock() {
  true
}

e2e_test_extra_hash() {
  grep '^helm-templates=' "$PROJECT_PATH/stackgres-k8s/ci/build/target/image-hashes.$(cat stackgres-k8s/ci/build/target/build_hash)" \
      | cut -d = -f 2
}

e2e_test_install() {
  k8s_async_cleanup
  kubectl create namespace "$CLUSTER_NAMESPACE"
  deploy_curl_pod "$CLUSTER_NAMESPACE"
}

e2e_test_uninstall() {
  k8s_async_cleanup

  kubectl create namespace "${OPERATOR_NAMESPACE}"
  install_operator_only
  wait_pods_running "$OPERATOR_NAMESPACE" 2
}

e2e_test() {
  run_test "Check that generated demo yamls are functional" test_yamls
  run_test "Check that generated demo packages are functional" test_packages
}

test_yamls() {
  OPERATOR_NAMESPACE="$(generate_operator_namespace)"
  ESCAPED_EXTENSIONS_REPOSITORY_URL="$(printf '%s' "$EXTENSIONS_REPOSITORY_URL" | sed 's/\&/\\\&/')"

  echo "Mocking stackgres-operator-demo.yml"
  OPERATOR_IMAGE_VERSION_LN="$(( $(grep -n 'name: OPERATOR_IMAGE_VERSION$' "${STACKGRES_YAMLS}/stackgres-operator-demo.yml" | cut -d : -f 1) + 1))"
  OPERATOR_JVM_IMAGE_VERSION_LN="$(( $(grep -n 'name: OPERATOR_JVM_IMAGE_VERSION$' "${STACKGRES_YAMLS}/stackgres-operator-demo.yml" | cut -d : -f 1) + 1))"
  OPERATOR_NATIVE_IMAGE_VERSION_LN="$(( $(grep -n 'name: OPERATOR_NATIVE_IMAGE_VERSION$' "${STACKGRES_YAMLS}/stackgres-operator-demo.yml" | cut -d : -f 1) + 1))"
  OPERATOR_IMAGE_TAG_LN="$(( $(grep -n 'name: stackgres/operator$' "${STACKGRES_YAMLS}/stackgres-operator-demo.yml" | cut -d : -f 1) + 2))"
  RESTAPI_IMAGE_TAG_LN="$(( $(grep -n 'name: stackgres/restapi$' "${STACKGRES_YAMLS}/stackgres-operator-demo.yml" | cut -d : -f 1) + 2))"
  ADMINUI_IMAGE_TAG_LN="$(( $(grep -n 'name: stackgres/admin-ui$' "${STACKGRES_YAMLS}/stackgres-operator-demo.yml" | cut -d : -f 1) + 2))"
  cat "${STACKGRES_YAMLS}/stackgres-operator-demo.yml" \
    | sed "s|name: stackgres$|name: $OPERATOR_NAMESPACE|" \
    | sed "s|namespace: stackgres$|namespace: $OPERATOR_NAMESPACE|" \
    | sed "/name: SGCONFIG_NAMESPACE$/{\$!{N;s/name: SGCONFIG_NAMESPACE\n\( *\)value: stackgres$/name: SGCONFIG_NAMESPACE\n\1value: $OPERATOR_NAMESPACE/;ty;P;D;:y}}" \
    | sed "s|image: \"\([^/]\+/\)\?stackgres/operator:.*\"$|image: '$OPERATOR_IMAGE_NAME'|" \
    | sed "${OPERATOR_IMAGE_VERSION_LN}s/value: .*$/value: '$IMAGE_TAG'/" \
    | sed "${OPERATOR_JVM_IMAGE_VERSION_LN}s/value: .*$/value: '${IMAGE_TAG%-jvm}-jvm'/" \
    | sed "${OPERATOR_NATIVE_IMAGE_VERSION_LN}s/value: .*$/value: '${IMAGE_TAG%-jvm}'/" \
    | sed "s|imagePullPolicy:.*[a-zA-Z].*$|imagePullPolicy: $E2E_OPERATOR_PULL_POLICY|" \
    | sed "s/{\(\"name\":\"stackgres\/operator\",[^}]\+\)\"tag\":\"[^\"]\+\"}/{\1\"tag\":\"$IMAGE_TAG\"}/" \
    | sed "s/{\(\"name\":\"stackgres\/restapi\",[^}]\+\)\"tag\":\"[^\"]\+\"}/{\1\"tag\":\"$IMAGE_TAG\"}/" \
    | sed "s/{\(\"name\":\"stackgres\/admin-ui\",[^}]\+\)\"tag\":\"[^\"]\+\"}/{\1\"tag\":\"$ADMINUI_IMAGE_TAG\"}/" \
    | sed "s/\"pullPolicy\":\"[^\"]\+\"/\"pullPolicy\":\"$E2E_OPERATOR_PULL_POLICY\"/g" \
    | sed '/image: \([^/]\+\/\)\?ongres\/.*$/{$!{N;s/image: \([^/]\+\/\)\?\(ongres\/.*\)\n\( *\)imagePullPolicy: .*$/image: \2\n\3imagePullPolicy: IfNotPresent/;ty;P;D;:y}}' \
    | if grep -q 'http%3A%2F%2Fstackgres-operator-extensions-cache\.stackgres%3FsetHttpScheme%3Dtrue' "${STACKGRES_YAMLS}/stackgres-operator-demo.yml"
      then
        sed "s|value: \"https://extensions.stackgres.io/postgres/repository?|value: \"$ESCAPED_EXTENSIONS_REPOSITORY_URL$(
          [ -z "${EXTENSIONS_REPOSITORY_URL#*\?}" ] && printf '\&' || printf '?')|" \
        | sed "s|http%3A%2F%2Fstackgres-operator-extensions-cache\.stackgres%3FsetHttpScheme%3Dtrue|http%3A%2F%2Fstackgres-operator-extensions-cache.$OPERATOR_NAMESPACE%3FsetHttpScheme%3Dtrue|"
      else
        cat
      fi \
    | sed "s|value: \"https://extensions.stackgres.io/postgres/repository\"$|value: \"$ESCAPED_EXTENSIONS_REPOSITORY_URL\"|" \
    > "${LOG_PATH}/stackgres-operator-demo.yml"

  grep -qF "name: $OPERATOR_NAMESPACE" "${LOG_PATH}/stackgres-operator-demo.yml"
  grep -qF "namespace: $OPERATOR_NAMESPACE" "${LOG_PATH}/stackgres-operator-demo.yml"
  grep -qF "value: $OPERATOR_NAMESPACE" "${LOG_PATH}/stackgres-operator-demo.yml"
  grep -qF "value: '$IMAGE_TAG'" "${LOG_PATH}/stackgres-operator-demo.yml"
  grep -qF "value: '${IMAGE_TAG%-jvm}-jvm'" "${LOG_PATH}/stackgres-operator-demo.yml"
  grep -qF "value: '${IMAGE_TAG%-jvm}'" "${LOG_PATH}/stackgres-operator-demo.yml"
  grep -qF "imagePullPolicy: $E2E_OPERATOR_PULL_POLICY" "${LOG_PATH}/stackgres-operator-demo.yml"
  if [ "$IMAGE_TAG" != "$ADMINUI_IMAGE_TAG" ]
  then
    grep -o -i "\"tag\":\"$IMAGE_TAG\"" "${LOG_PATH}/stackgres-operator-demo.yml" | wc -l | grep -qxF 2
    grep -o -i "\"tag\":\"$ADMINUI_IMAGE_TAG\"" "${LOG_PATH}/stackgres-operator-demo.yml" | wc -l | grep -qxF 1
  else
    grep -o -i "\"tag\":\"$IMAGE_TAG\"" "${LOG_PATH}/stackgres-operator-demo.yml" | wc -l | grep -qxF 3
  fi
  grep -qF "\"pullPolicy\":\"$E2E_OPERATOR_PULL_POLICY\"" "${LOG_PATH}/stackgres-operator-demo.yml"
  if grep -q 'http%3A%2F%2Fstackgres-operator-extensions-cache\.stackgres%3FsetHttpScheme%3Dtrue' "${STACKGRES_YAMLS}/stackgres-operator-demo.yml"
  then
    grep -qF "value: \"$EXTENSIONS_REPOSITORY_URL$(
      [ -z "${EXTENSIONS_REPOSITORY_URL#*\?}" ] && printf '&' || printf '?')" "${LOG_PATH}/stackgres-operator-demo.yml"
    grep -qF "http%3A%2F%2Fstackgres-operator-extensions-cache.$OPERATOR_NAMESPACE%3FsetHttpScheme%3Dtrue" "${LOG_PATH}/stackgres-operator-demo.yml"
  fi
  grep -qF "value: \"$EXTENSIONS_REPOSITORY_URL\"" "${LOG_PATH}/stackgres-operator-demo.yml"

  echo "Installing operator.yml"
  kubectl create -n "${OPERATOR_NAMESPACE}" -f "${LOG_PATH}/stackgres-operator-demo.yml"

  kubectl get jobs -n "$OPERATOR_NAMESPACE" -o name \
    | while read JOB
    do
      kubectl wait -n "$OPERATOR_NAMESPACE" "$JOB" --for condition=Complete --timeout "${E2E_TIMEOUT}s"
    done

  if ! wait_services_available "$OPERATOR_NAMESPACE" 1 "^stackgres-operator$"
  then
    fail "The demo StackGres operator service was not available."
  else
    success "The demo StackGres operator service was available."
  fi

  if ! wait_services_available "$OPERATOR_NAMESPACE" 1 "^stackgres-restapi$"
  then
    fail "The demo StackGres restapi service was not available."
  else
    success "The demo StackGres restapi service was available."
  fi

  if grep -q http%3A%2F%2Fstackgres-operator-extensions-cache\.stackgres%3FsetHttpScheme%3Dtrue "${STACKGRES_YAMLS}/stackgres-operator-demo.yml"
  then
    if ! wait_services_available "$OPERATOR_NAMESPACE" 1 "^stackgres-operator-extensions-cache$"
    then
      fail "The demo StackGres extensions cache service was not available."
    else
      success "The demo StackGres extensions cache service was available."
    fi
  fi

  echo "Creating demo cluster"
  kubectl create --namespace "${CLUSTER_NAMESPACE}" -f "${STACKGRES_YAMLS}/stackgres-simple-config-demo.yml" 
  kubectl create --namespace "${CLUSTER_NAMESPACE}" -f "${STACKGRES_YAMLS}/stackgres-simple-cluster-demo.yml"

  if wait_pods_running "${CLUSTER_NAMESPACE}" 2 "simple-[^[:space:]]\+"
  then
    success "The demo StackGres cluster pods are running."
  else
    fail "The demo StackGres cluster pods are not running."
  fi

  echo "Creating MinIO resources"
  kubectl create --namespace "${CLUSTER_NAMESPACE}" -f "${STACKGRES_YAMLS}/minio-demo.yml"

  if wait_pods_running "${CLUSTER_NAMESPACE}" 1 "minio-[^[:space:]]\+"
  then
    success "The demo MinIO pod is running."
  else
    fail "The demo MinIO pod is not running."
  fi

  echo "Testing Cluster readability"
  if kubectl exec simple-0 -n "${CLUSTER_NAMESPACE}" -c postgres-util -- psql -Antqc 'Select 1'
  then
    success "The demo StackGres cluster primary is available."
  else
    fail "The demo StackGres cluster primary is not available."
  fi
  if kubectl exec simple-1 -n "${CLUSTER_NAMESPACE}" -c postgres-util -- psql -Antqc 'Select 1'
  then
    success "The demo StackGres cluster secondary is available."
  else
    fail "The demo StackGres cluster secondary is not available."
  fi

  deploy_curl_pod "$CLUSTER_NAMESPACE"
  check_namespace

  echo "Deleting MinIO resources"
  kubectl delete --namespace "${CLUSTER_NAMESPACE}" -f "${STACKGRES_YAMLS}/minio-demo.yml"

  if wait_pods_terminated "${CLUSTER_NAMESPACE}" 0 "minio-[^[:space:]]\+"
  then
    success "The demo MinIO pod has been terminated."
  else
    fail "The demo MinIO pod has not been terminated."
  fi

  echo "Deleting demo cluster"
  kubectl delete --namespace "${CLUSTER_NAMESPACE}" -f "${STACKGRES_YAMLS}/stackgres-simple-cluster-demo.yml"
  kubectl delete --namespace "${CLUSTER_NAMESPACE}" -f "${STACKGRES_YAMLS}/stackgres-simple-config-demo.yml" 

  if wait_pods_terminated "${CLUSTER_NAMESPACE}" 0 "simple-[^[:space:]]\+"
  then
    success "The demo StackGres cluster pods have been terminated."
  else
    fail "The demo StackGres cluster pods have not been terminated."
  fi

  echo "Deleting demo operator"
  kubectl delete --ignore-not-found --namespace "${OPERATOR_NAMESPACE}" -f "${LOG_PATH}/stackgres-operator-demo.yml"

  if wait_until is_demo_operator_namespace_removed
  then
    success "The demo StackGres operator namespace has been removed."
  else
    fail "The demo StackGres operator namespace has not been removed."
  fi
}

is_demo_operator_namespace_removed() {
  ! kubectl get namespace "${OPERATOR_NAMESPACE}"
}

test_packages() {
  OPERATOR_NAMESPACE="$(generate_operator_namespace)"

  echo "Installing operator package"
  kubectl create namespace "${OPERATOR_NAMESPACE}"

  helm install --namespace "${OPERATOR_NAMESPACE}" stackgres-operator \
    "${STACKGRES_PACKAGES}/stackgres-operator.tgz" \
    --set-string operator.image.name="${OPERATOR_IMAGE_NAME%:*}" --set-string operator.image.tag="${OPERATOR_IMAGE_NAME#*:}" \
    --set-string "operator.image.pullPolicy=$E2E_OPERATOR_PULL_POLICY" \
    --set-string restapi.image.name="${RESTAPI_IMAGE_NAME%:*}" --set-string restapi.image.tag="${RESTAPI_IMAGE_NAME#*:}" \
    --set-string "restapi.image.pullPolicy=$E2E_OPERATOR_PULL_POLICY" \
    --set-string adminui.image.name="${ADMINUI_IMAGE_NAME%:*}" --set-string adminui.image.tag="${ADMINUI_IMAGE_NAME#*:}" \
    --set-string "adminui.image.pullPolicy=$E2E_OPERATOR_PULL_POLICY" \
    --set-string "extensions.repositoryUrls[0]=$EXTENSIONS_REPOSITORY_URL" \
    --set adminui.service.type=LoadBalancer

  if ! wait_services_available "$OPERATOR_NAMESPACE" 1 "^stackgres-operator$"
  then
    fail "The StackGres operator service was not available."
  else
    success "The StackGres operator service was available."
  fi

  if ! wait_services_available "$OPERATOR_NAMESPACE" 1 "^stackgres-restapi$"
  then
    fail "The StackGres restapi service was not available."
  else
    success "The StackGres restapi service was available."
  fi

  if [ "$(helm get values -n "$OPERATOR_NAMESPACE" stackgres-operator -o json | jq .extensions.cache.enabled)" = true ]
  then
    if ! wait_services_available "$OPERATOR_NAMESPACE" 1 "^stackgres-operator-extensions-cache$"
    then
      fail "The demo StackGres extensions cache service was not available."
    else
      success "The demo StackGres extensions cache service was available."
    fi
  fi

  echo "Creating demo package cluster"
  helm install --namespace "${CLUSTER_NAMESPACE}" "${CLUSTER_NAME}" \
    "${STACKGRES_PACKAGES}/stackgres-cluster-demo.tgz" \
    --set cluster.sgInstanceProfile=size-s \
    --set cluster.instances=2 \
    --set nonProductionOptions.disableClusterPodAntiAffinity=true \
    --set nonProductionOptions.disablePatroniResourceRequirements=true \
    --set nonProductionOptions.disableClusterResourceRequirements=true

  if wait_pods_running "${CLUSTER_NAMESPACE}" 2 "$CLUSTER_NAME-[^[:space:]]\+"
  then
    success "The demo StackGres cluster pods are running."
  else
    fail "The demo StackGres cluster pods are not running."
  fi

  echo "Testing Cluster readability"
  if kubectl exec "${CLUSTER_NAME}-0" -n "${CLUSTER_NAMESPACE}" -c postgres-util -- psql -Antqc 'Select 1'
  then
    success "The demo package StackGres cluster primary is available."
  else
    fail "The demo package StackGres cluster primary is not available."
  fi
  if kubectl exec "${CLUSTER_NAME}-1" -n "${CLUSTER_NAMESPACE}" -c postgres-util -- psql -Antqc 'Select 1'
  then
    success "The demo package StackGres cluster secondary is available."
  else
    fail "The demo package StackGres cluster secondary is not available."
  fi

  check_namespace

  echo "Deleting demo package cluster"
  helm uninstall --namespace "${CLUSTER_NAMESPACE}" "${CLUSTER_NAME}"

  if wait_pods_terminated "${CLUSTER_NAMESPACE}" 0 "simple-[^[:space:]]\+"
  then
    success "The demo package StackGres cluster pods have been terminated."
  else
    fail "The demo package StackGres cluster pods have not been terminated."
  fi
}

check_namespace() {
  if wait_until check_returned_namespaces
  then
    success "Namespace endpoint returned all namespaces"
    return 0
  else
    fail "Namespace endpoint not return all namespaces"
  fi
}

check_returned_namespaces() {
  local NAMESPACES_IN_RESPONSE
  local NAMESPACES_IN_K8S

  NAMESPACES_IN_RESPONSE="$(run_curl -r "stackgres/namespaces" -n "$CLUSTER_NAMESPACE" \
    | jq -M -S 'sort_by(.)[]' )"

  NAMESPACES_IN_K8S="$(kubectl get ns -o json \
    | jq -M -S '.items[].metadata.name')"

  [ "$NAMESPACES_IN_RESPONSE" = "$NAMESPACES_IN_K8S" ]
}
